/************************************************************************
 * libspr - Ragnarok Sprite File Library                                *
 * 2012 (c) FatalEror                                                   *
 *                                                                      *
 * This program is free software, you can redistribute it and/or modify *
 * it under the terms of the GNU General Public License as published by *
 * the Free Software Foundation, either version 3 of the License, or    *
 * (at your option) any later version.                                  *
 ************************************************************************/

//Built libspr in Unicode
#ifndef UNICODE
#define UNICODE
#endif

#pragma warning(disable : 4018 4333 4996)

#include "spr.h"

SprFile::SprFile()
{

}

SprFile::~SprFile()
{
	for (int i = 0; i < (int)m_content.size(); i++)
		if (m_content.at(i).img_data)
			delete[] m_content.at(i).img_data;
	m_content.clear();
}

// Read spr data from buffer
bool SprFile::read(uint8_t *data, uint32_t size)
{
	//Store header info
	memcpy(&m_header, data, sizeof(m_header));
	if (m_header.signature != 0x5053) //Invalid SPR File
		return false;

	int o = sizeof(m_header);
	for (int i = 0; i < (int)m_header.image_count; i++) {
		SprContent image_content;

		//Image information(width, height, size)
		if (o + CONTENT_HEADER_SIZE > size) return false; //invalid, offset is bigger than buffer size
		memcpy(&image_content, data+o, CONTENT_HEADER_SIZE);
		o += CONTENT_HEADER_SIZE;

		//Pixel data
		if (o + image_content.img_size > size) return false; //invalid, offset is bigger than buffer size
		image_content.img_data = new uint8_t[image_content.img_size];
		memset(image_content.img_data, '\0', image_content.img_size);
		memcpy(image_content.img_data, data+o, image_content.img_size);
		o += image_content.img_size;

		m_content.push_back(image_content);
	}
	
	//Palette data
	memcpy(m_palette, data+size-1024, sizeof(m_palette));

	return true;
}

// Read spr data from file
#ifdef UNICODE
bool SprFile::read(wchar_t *file_name)
#else
bool SprFile::read(char *file_name)
#endif
{
	fstream f_input;
	f_input.open(file_name, ios::in | ios::binary);
	if (!f_input.is_open())
		return false;

	f_input.seekg(0, ios::end);
	uint32_t size = (uint32_t)f_input.tellg();
	f_input.seekg(0, ios::beg);

	//Valid SPR files have size more than (Header[8] + Palette[1024])
	if (size < sizeof(m_header) + sizeof(m_palette))
		return false;
	
	//Store file data into buffer and read it
	uint8_t *data = new uint8_t[size];
	f_input.read((char*)data, size);
	read(data, size);
	delete[] data;

	f_input.close();
	return true;
}

uint8_t *SprFile::bmp_get_data(uint32_t ncontent)
{
	SprContent spr_data = m_content.at(ncontent);
	uint32_t size_row = spr_data.img_width*3 + (4 - (spr_data.img_width*3)%4)%4;
	uint32_t size = 54 + spr_data.img_height*size_row;
	uint8_t *buff_data = new uint8_t[size];

	//BMP 24-Bits
	memset(buff_data, NULL, size);
	buff_data[0]  = (uint8_t) ('B');
	buff_data[1]  = (uint8_t) ('M');
	buff_data[2]  = (uint8_t) (size);
	buff_data[3]  = (uint8_t) (size>>8);
	buff_data[4]  = (uint8_t) (size>>16);
	buff_data[5]  = (uint8_t) (size>>24);
	buff_data[10] = (uint8_t) (54);
	buff_data[14] = (uint8_t) (40);
	buff_data[18] = (uint8_t) (spr_data.img_width);
	buff_data[19] = (uint8_t) (spr_data.img_width>>8);
	buff_data[20] = (uint8_t) (spr_data.img_width>>16);
	buff_data[21] = (uint8_t) (spr_data.img_width>>24);
	buff_data[22] = (uint8_t) (spr_data.img_height);
	buff_data[23] = (uint8_t) (spr_data.img_height>>8);
	buff_data[24] = (uint8_t) (spr_data.img_height>>16);
	buff_data[25] = (uint8_t) (spr_data.img_height>>24);
	buff_data[26] = (uint8_t) (1);
	buff_data[28] = (uint8_t) (24);

	//Convert from SPR to BMP
	uint8_t *row_data = new uint8_t[size_row];
	memset(row_data, NULL, size_row);
	int x = 0, y = 0;
	for (int n = 0; n < (int)spr_data.img_size; n++) {
		if (x >= spr_data.img_width) {
			for (int i = 0; i < size_row; i++)
				buff_data[54+(spr_data.img_height-y-1)*size_row+i] = row_data[i];
			memset(row_data, NULL, size_row);
			y++; x = 0;
		}
		if (spr_data.img_data[n] == 0) {
			for (int b = 0; b < spr_data.img_data[n+1]; b++) {
				row_data[x*3]   = (uint8_t) (m_palette[spr_data.img_data[n]]>>16);
				row_data[x*3+1] = (uint8_t) (m_palette[spr_data.img_data[n]]>>8);
				row_data[x*3+2] = (uint8_t) (m_palette[spr_data.img_data[n]]);
				x++;
				if (x >= spr_data.img_width) {
					for (int i = 0; i < size_row; i++)
						buff_data[54+(spr_data.img_height-y-1)*size_row+i] = row_data[i];
					memset(row_data, NULL, size_row);
					y++; x = 0;
				}
			} n++;
		} else {
			row_data[x*3]   = (uint8_t) (m_palette[spr_data.img_data[n]]>>16);
			row_data[x*3+1] = (uint8_t) (m_palette[spr_data.img_data[n]]>>8);
			row_data[x*3+2] = (uint8_t) (m_palette[spr_data.img_data[n]]);
			x++;
		}
	} delete[] row_data;

	return buff_data;
}